路由主要負責將請求轉送到對應的處理程序中。當客戶端的請求符合設定中的 URL 規則時,就會自動執行指定的行為。今天會由簡單到複雜,介紹幾種設定路由的方式。
在介紹中介層的時候,有使用到 app.Map("/ironman")
這樣的方法,就是最簡單設定路由的方式了。
private static void HandleMapIronman(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Map Ironman");
});
}
public void Configure(IApplicationBuilder app)
{
app.Map("/ironman", HandleMapIronman);
}
但當應用程式越來越複雜之後,要用這種方式一個一個指定會非常困難,所以 ASP.NET Core 有提供一個路由的中介層,讓開發人員可以彈性的定義路由。
開發人員也可以利用中介層來彈性的定義路由。要使用路由中介層 RouterMiddleware,需要搭配 RouteBuilder 來做設定。例如下列的 Startup
設定:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddRouting();
}
public void Configure(IApplicationBuilder app)
{
var routeBuilder = new RouteBuilder(app);
routeBuilder.DefaultHandler = new RouteHandler((context) =>
{
var routeValues = context.GetRouteData().Values;
return context.Response.WriteAsync(
$"Hello! Route values: {string.Join(", ", routeValues)}");
});
routeBuilder.MapRoute(
name: "routing example",
template: "dotnet/{type:regex(^core|mvc|webapi$)}/{available:bool}"
);
routeBuilder.MapGet("ithome/{title}", (context) =>
{
var title = context.GetRouteValue("title");
return context.Response.WriteAsync($"Your Title: {title}");
});
app.UseRouter(routeBuilder.Build());
}
}
這段程式碼做了幾件事情:
routeBuilder.DefaultHandler = new RouteHandler
:設定一個處理程序,用來執行除了 Map{Verb}
這種有直接提供對應程序的請求。routeBuilder.MapRoute
:設定一組路由規則。第一個參數是路由名稱,第二個則是符合這組路由的 URL 定義。也可以針對每一個參數做限制,更多限制條件可以參可官方文件。routeBuilder.MapGet
:設定符合 URL 規則而且是 HTTP GET 請求的對應處理程序。需要特別注意,路由規則是有順序性的,如果客戶端的請求同時符合多組路由規則,會執行第一組加入的路由規則。
這段設定對應到的 URL 與輸出結果:
URL | Output |
---|---|
/dotnet/core/true | Hello! Route values: [type, core], [available, true] |
/dotnet/webapi/false | Hello! Route values: [type, webapi], [available, false] |
/dotnet/signalr/true | |
/ithome/ironman2018 | Your Title: ironman2018 |
使用 MVC 路由的方式跟使用中介層有 87% 像,只是多了指定對應的 Controller
和 Action
的設定。設定 MapRoute
的方式也跟使用中介層時一樣。
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}
public void Configure(IApplicationBuilder app)
{
app.UseMvc(routes =>
{
routes.MapRoute(
name: "mvc routing",
template: "about",
defaults: new { controller = "Home", action = "About" }
);
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}"
);
});
}
}
除了在 Startup.cs
中做全域的路由設定外,也可以在 Controller
或 Action
中用 RouteAttribute
或 Http{Verb}
來做個別的路由設定。
屬性路由的優先度比
Startup
中設定的路由規則還高,所以就算符合Startup
中的路由規則也不會執行。
例如以下的屬性路由設定,可以做到跟 {controller=Home}/{action=Index}
類似的效果:
public class HomeController : Controller
{
[Route("")]
[Route("Home")]
[Route("Home/Index")]
public IActionResult Index()
{
return View();
}
[Route("Home/About")]
public IActionResult About()
{
return View();
}
[Route("Home/Contact")]
public IActionResult Contact()
{
return View();
}
}
或者也可以把路由共用的邏輯往上拉一層,變成 Controller
的 attribute:
[Route("Home")]
public class HomeController : Controller
{
[Route("")]
[Route("Index")]
public IActionResult Index()
{
return View();
}
[Route("About")]
public IActionResult About()
{
return View();
}
[Route("Contact")]
public IActionResult Contact()
{
return View();
}
}
也可以透過 Http{Verb}
屬性來對路由做 HTTP 動詞的限制,這類屬性的使用方式跟 RouteAttribute
差不多。